/**
 * create by zhangpu
 * date:2015年4月11日
 */
package com.acooly.module.openapi.client.api;

import com.acooly.module.openapi.client.api.exception.ApiClientException;
import com.acooly.module.openapi.client.api.exception.ApiServerException;
import com.acooly.module.openapi.client.api.marshal.ApiMarshal;
import com.acooly.module.openapi.client.api.marshal.ApiUnmarshal;
import com.acooly.module.openapi.client.api.message.ApiMessage;
import com.acooly.module.openapi.client.api.message.PostRedirect;
import com.acooly.module.openapi.client.api.transport.Transport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

import java.util.Map;

/**
 * API SDK 执行器 抽象实现
 * 
 * @author zhangpu
 *
 */
public abstract class AbstractApiServiceClient<R extends ApiMessage, T extends ApiMessage, N extends ApiMessage, X extends ApiMessage>
		implements ApiServiceClient<R, T, N, X> {

	private static Logger logger = LoggerFactory.getLogger(AbstractApiServiceClient.class);

	@Override
	public T execute(R request) {
		try {
			beforeExecute(request);
			String requestMessage = getRequestMarshal().marshal(request);
			logger.info("请求:" + requestMessage);
			String responseMessage = getTransport().exchange(requestMessage);
			logger.info("响应:" + responseMessage);
			T t = getResponseUnmarshal().unmarshal(responseMessage, request.getService());
			afterExecute(t);
			return t;
		} catch (ApiServerException ose) {
			logger.error("服务器:" + ose.getMessage(), ose);
			throw ose;
		} catch (ApiClientException oce) {
			logger.error("客户端:" + oce.getMessage(), oce);
			throw oce;
		} catch (Exception e) {
			logger.error("内部错误:" + e.getMessage(), e);
			throw new ApiClientException("内部错误:" + e.getMessage());
		}
	}

	@Override
	public N notice(Map<String, String> notifyData, String serviceKey) {
		try {
			N notify = getNoticeUnmarshal().unmarshal(notifyData, serviceKey);
			afterNotice(notify);
			return notify;
		} catch (ApiClientException oce) {
			logger.warn("客户端异常:" + oce.getMessage(), oce);
			throw oce;
		} catch (Exception e) {
			logger.warn("内部错误:" + e.getMessage(), e);
			throw new ApiClientException("内部错误:" + e.getMessage());
		}
	}

	/**
	 * @param notify
	 */
	protected void afterNotice(N notify) {

	}

	/**
	 * 默认实现为：跳转通知结构与异步通知相同。
	 */
	@Override
	public X result(Map<String, String> notifyData, String serviceKey) {
		try {
			return getReturnUnmarshal().unmarshal(notifyData, serviceKey);
		} catch (ApiClientException oce) {
			logger.warn("客户端异常:" + oce.getMessage(), oce);
			throw oce;
		} catch (Exception e) {
			logger.warn("内部错误:" + e.getMessage(), e);
			throw new ApiClientException("内部错误:" + e.getMessage());
		}
	}

	@Override
	public String redirectGet(R request) {
		try {
			String requestMessage = getRedirectMarshal().marshal(request);
			return getRedirectGateway() + "?" + requestMessage;
		} catch (ApiServerException ose) {
			logger.warn("服务器错误:" + ose.getMessage(), ose);
			throw ose;
		} catch (ApiClientException oce) {
			logger.warn("客户端异常:" + oce.getMessage(), oce);
			throw oce;
		} catch (Exception e) {
			logger.warn("内部错误:" + e.getMessage(), e);
			throw new ApiClientException("内部错误:" + e.getMessage());
		}
	}

	/**
	 * 同步请求前置处理
	 * 
	 * @param request
	 */
	protected void beforeExecute(R request) {
		MDC.put("service", request.getService());
	}

	/**
	 * 同步请求后置处理
	 * 
	 * @param response
	 */
	protected void afterExecute(T response) {

	}

	/**
	 * 请求报文marshal
	 * 
	 * @return
	 */
	protected abstract ApiMarshal<String, R> getRequestMarshal();

	/**
	 * 响应报文unmarshal
	 * 
	 * @return
	 */
	protected abstract ApiUnmarshal<T, String> getResponseUnmarshal();

	/**
	 * 跳转请求marshal
	 * 
	 * @return
	 */
	protected abstract ApiMarshal<String, R> getRedirectMarshal();

	protected abstract ApiUnmarshal<N, Map<String, String>> getNoticeUnmarshal();

	protected abstract ApiUnmarshal<X, Map<String, String>> getReturnUnmarshal();

	protected String getRedirectGateway() {
		return null;
	}

	/**
	 * 通讯组件
	 * 
	 * @return
	 */
	protected abstract Transport getTransport();

	@Override
	public PostRedirect redirectPost(R request) {
		throw new UnsupportedOperationException();
	}

}
